# -*- coding: utf-8 -*-
"""
@Time ： 2021/8/5 下午1:49
@Auth ： Puzzle
@File ： public.py
@IDE ：  PyCharm
@Email： 979497249@qq.com
@Blog:   https://blog.csdn.net/Yanskang

    基于 odoo 底层Home 进行扩展，对书写前后端分离借口做简单化开发优化。

"""
import logging

from typing import List, Optional
from dtcloud.http import request
from dtcloud.osv import expression
from .convert import converts

_logger = logging.getLogger(__name__)


class CRUDBase:
    _model: str = None
    _order: str = "id desc"
    _fields: Optional[List[str]] = None
    _domains: Optional[List[List[str]]] = None
    _offset_fields = ['write_uid', '__last_update', 'create_uid', 'display_name']

    @classmethod
    def home_public_list(cls, domains=None, field_list=None, model=None, **kwargs):
        """
        列表详情读取
        :param model: 模型
        :param field_list: 字段列表
        :param kw: 参数
        :param domains: 过滤条件
        :return: 列表数据，显示行数
        """
        field_list = field_list or cls._fields
        domains = domains or cls._domains
        model = model or cls._model

        page = int(kwargs.get("page", 1) or 1)
        limit = int(kwargs.get("limit") or kwargs.get("perPage") or kwargs.get('pageSize', 10) or 10)
        offset = (page - 1) * limit
        order = kwargs.get('order') or cls._order

        domain = cls.home_public_domain(domains, model, **kwargs)
        print(f"\033[35m --- {domain} ---\033[0m")
        pool = request.env
        records = pool[model].with_user(request.uid).sudo().search(
            domain, limit=limit, offset=offset, order=order)
        count = pool[model].with_user(request.uid).sudo().search_count(domain)

        record_list = cls.home_public_read(records, field_list)
        return record_list, count

    @classmethod
    def home_public_domain(cls, domains=None, model=None, **kwargs):
        """
        解析domain 语句，列表详情读取部件之一
        """
        offset = ['limit', 'page', 'order']
        model = model or cls._model
        fields = request.env[model].sudo().fields_get()

        domain = []
        if domains:
            domain = domains
        if kwargs.get("start_time"):
            domain.append(('start_time', '>=', kwargs.get('start_time')))
        if kwargs.get("end_time"):
            domain.append(('end_time', '<=', kwargs.get("end_time")))
        if kwargs.get("active"):
            domain.append(('active', '=', 0))
        for i in kwargs:
            if not kwargs[i]:
                continue
            if i not in fields or i in offset:
                continue
            field_type = fields[i]['type']
            if field_type == "integer":
                domain = expression.AND([domain, [(i, '=', int(kwargs[i]))]])
            if field_type == 'char' or field_type == 'text' or field_type == 'float':
                domain = expression.AND([domain, [(i, 'ilike', kwargs[i])]])
            elif field_type == 'one2many' or field_type == "many2many":
                if len(kwargs[i]) == 1 and isinstance(kwargs[i], str):
                    domain = expression.AND([domain, [(i, 'in', [eval(kwargs[i])])]])
                else:
                    domain = expression.AND([domain, [(i, 'in', list(eval(kwargs[i])))]])
            elif field_type == 'many2one':
                if kwargs[i].isdigit():
                    domain = expression.AND([domain, [(i, '=', int(kwargs[i]))]])
                else:
                    domain = expression.AND([domain, [(i, 'ilike', kwargs[i])]])
            elif field_type == 'selection':
                domain = expression.AND([domain, [(i, '=', kwargs[i])]])
            elif field_type == 'boolean':
                if isinstance(kwargs[i], str):
                    if kwargs[i] == 'true' or kwargs[i] == 'True':
                        domain = expression.AND([domain, [(i, '=', True)]])
                    elif kwargs[i] == 'false' or kwargs[i] == 'False':
                        domain = expression.AND([domain, [(i, '=', False)]])
                else:
                    domain = expression.AND([domain, [(i, '=', kwargs[i])]])

        return domain

    @classmethod
    def home_public_read(cls, records, field_list):
        """
        读取列表数据部件之一，返回对应数据集合，自动编码序号 RecordNumber
        """
        fields = records._fields
        field_list = field_list or list(records._fields)
        field_list = list(filter(lambda ele: ele not in cls._offset_fields, field_list))

        records_list = []
        active = fields.get('active', False)
        if active:
            records = records.filtered(lambda x: x.active and x.active is True)
        for rec in records:
            field_read = {}
            for field in field_list:
                field_ins = fields[field]
                if field_ins.type in converts:
                    field_read[field] = converts[field_ins.type].to_read(rec, field_ins)
                else:
                    field_read[field] = field_ins.convert_to_read(rec[field], rec)
            records_list.append(field_read)
        return records_list

    @classmethod
    def home_public_create_dict(cls, data, model=None):
        """
        返回正确的创建数据集合，易扩展
        """
        model = model or cls._model
        fields = request.env[model].with_user(request.uid).fields_get()
        keys = []
        for rec in data:
            # 空值 字段不存在
            if rec not in fields.keys():
                keys.append(rec)
                continue

            data[rec] = converts[fields[rec]['type']].to_field(data[rec])

        for k in keys:
            del data[k]
        if not data:
            return None
        return request.env[model].sudo().create(data)

    @classmethod
    def home_public_write_dict(cls, data, model=None):
        """
        获取正确的更新数据集合，不直接更新，易扩展
        """
        model = model or cls._model
        fields = request.env[model].with_user(request.uid).fields_get()
        keys = []
        # 过滤字段
        filter_field_list = ['create_uid']
        for filter_filed in filter_field_list:
            if filter_filed in data:
                del data[filter_filed]
        for rec in data:
            # 字段不存在
            if rec not in fields.keys():
                keys.append(rec)
                continue

            try:
                data[rec] = converts[fields[rec]['type']].to_field(data[rec])
            except KeyError:
                data[rec] = data[rec]

        for k in keys:
            del data[k]

        # 按ID搜索
        record = request.env[model].sudo().browse(int(data["id"]))
        del data['id']
        if not data:
            return None
        # 执行更新
        return record.write(data)

    @classmethod
    def home_public_unlink(cls, vals):
        """
        归档数据，使其不可见，失灵添加 active = fields.Boolean() 字段生效
        """
        try:
            # 是否强制删除
            is_force_delete = vals.get("is_force_delete", False)
            # 该模型下是否有关联
            is_unlink = 1
            Model = request.env[cls._model].with_user(request.uid).browse(eval(vals.get('id')))
            fields = Model.fields_get()
            for field_name, field_property in fields.items():
                # 字段类型
                field_type = field_property.get('type')
                if field_type in ['one2many', 'many2many'] and Model[field_name]:
                    is_unlink = 0
            if is_unlink == 1 or is_force_delete or cls._model in 'res.users':
                Model.toggle_active()
                return 1
            if is_unlink == 0:
                return -1
        except Exception as r:
            _logger.warning("删除失败", r)
            return -2

    @classmethod
    def home_public_read_one(cls, rid, field_list, **kwargs):
        """
        获取单据详情数据，返回字典集合
        """
        res = request.env[cls._model].with_user(request.uid).sudo().browse(int(rid))
        response_type = kwargs.get('response_type')
        if response_type == "id":
            record = cls.home_public_read_id(res, field_list)[0]
        else:
            record = cls.home_public_read(res, field_list)[0]
        return record

    @classmethod
    def home_public_read_one_sudo(cls, rid, field_list, **kwargs):
        """
        获取单据详情数据，返回字典集合
        """
        res = request.env[cls._model].sudo().browse(int(rid))
        response_type = kwargs.get('response_type')
        if response_type == "id":
            record = cls.home_public_read_id(res, field_list)[0]
        else:
            record = cls.home_public_read(res, field_list)[0]
        return record

    @classmethod
    def home_public_read_one_dedicated(cls, records, field_list):
        """
        获取单据详情数据，返回字典集合
        """
        record = cls.home_public_read_dedicated(records, field_list)[0]
        return record

    @classmethod
    def home_public_read_many_list(cls, records, keys=None):
        """
        获取数据集的列表id 和 name
        """
        many_list = []
        for rec in records:
            data = {
                'id': rec.id,
                'name': rec.name
            }
            if keys:
                for k in keys:
                    data[k] = rec[k]
                many_list.append(data)
            else:
                many_list.append(data)
        return many_list

    @classmethod
    def many_to_one_or_select(cls, model, field_list, keys=None):
        """
        处理前段显示的选择类型使用，传入字段自动判断转化分析
        """
        fields = request.env[model].fields_get()
        fdict = {}
        for f in field_list:
            filed_type = fields[f]['type']
            if filed_type == 'many2one' or filed_type == "many2many" or filed_type == 'one2many':
                fdict[f] = cls.home_public_read_many_list(
                    request.env[fields[f]['relation']].with_user(request.uid).search([]), keys)
            elif filed_type == "selection":
                fdict[f] = []
                for s in fields[f]['selection']:
                    fdict[f].append({
                        'id': s[0],
                        'name': s[1]
                    })
        return fdict

    @classmethod
    def home_group_list(cls, record_list, group):
        rlist = []
        for rec in record_list:
            if len(rlist) == 0:
                rlist.append({
                    group: rec[group],
                    'child': [rec]
                })
            else:
                active = False
                for r in rlist:
                    if r[group] == rec[group]:
                        r['child'].append(rec)
                        active = True
                if not active:
                    rlist.append({
                        group: rec[group],
                        'child': [rec]
                    })
        return rlist

    @classmethod
    def models_field_help(cls, record, field_list):
        fields = record.with_user(request.uid).fields_get()
        field_read = []
        num = 0
        for f in field_list:
            num += 1
            filed_type = fields[f]['type']
            if filed_type == 'selection':
                field_read.append({
                    'name': f,
                    'state': record[f],
                    'data': eval(fields[f]['help']),
                    'num': num
                })
        return field_read

    @classmethod
    def home_public_delete(cls, rids, model=None):
        """id单个删除、批量删除"""
        model = model or cls._model
        return request.env[model].sudo().browse(rids).unlink()
